
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.rms.RecordStore;

public class ReversiCanvas extends GameCanvas implements Runnable {

    private final int UNITY;
    private final int UNITX;
    private Graphics g;
    private Image imgGround;
    private Image imgBlack;
    private Image imgWhite;
    private Game game;
    private int color;
    private String msgStr = "None";
    private int whiteNum = 0;
    private int blackNum = 0;
    private boolean isStart = false;
    private int keyState = 0;
    private int rectColor;
    private int x;
    private int y;
    private RecordStore rs = null;
    private RecordStore gameSetting = null;
    private boolean isSave = true;
    private Thread t;
    private ReversiSprite mSprite;
    private boolean soundOn = true;
    private boolean animationOn = true;

    
    //constructor
    public ReversiCanvas(Game game) {
        super(true);

        this.game = game;
        gameSeting();
        g = this.getGraphics();
        x = 1;
        y = 1;
        rectColor = 0x00ff00;

        int unitY = getHeight() > getWidth() ? 12 : 10;
        int unitX = getHeight() > getWidth() ? 10 : 12;
        if (getHeight() == getWidth()) {
            unitX = unitY = 10;
        }

        UNITY = getHeight() / unitY;
        UNITX = getWidth() / unitX;
        try {
            mSprite = createSprite(x, y);

            //background image
            imgGround = Image.createImage("/ground.png");
            imgGround = TransImage.scale(imgGround, getWidth(), getHeight());

            //black piece
            imgBlack = Image.createImage("/black.png");
            imgBlack = TransImage.scale(imgBlack, UNITX * 3 / 4, UNITY * 3 / 4);

            //white piece
            imgWhite = Image.createImage("/white.png");
            imgWhite = TransImage.scale(imgWhite, UNITX * 3 / 4, UNITY * 3 / 4);
            
            //play background music
            game.playBackGroundSound("Background.mid", soundOn);


        } catch (java.io.IOException e) {
        } catch (java.lang.IllegalArgumentException e) {
            e.printStackTrace();
        }
    }

    public Game getGame() {
        return game;
    }

    //key pressed
    public void keyPressed() {
        keyState = getKeyStates();
        if (game.getState() != AllDef.RUN) {
            return;
        }
        if ((keyState & UP_PRESSED) != 0) {
            if (x != 1) {
                x--;
            }
        } else if ((keyState & DOWN_PRESSED) != 0) {
            if (x != 8) {
                x++;
            }
        } else if ((keyState & RIGHT_PRESSED) != 0) {
            if (y != 8) {
                y++;
            }
        } else if ((keyState & LEFT_PRESSED) != 0) {
            if (y != 1) {
                y--;
            }
        } else if ((keyState & FIRE_PRESSED) != 0) {
            try {
                //black turn. Set black piece
                if (game.getTurn() == AllDef.BLACK) {
                    if (game.getBlack().setChess(x, y)) {
                        game.playSound("/Click3.wav", soundOn);
                        game.setTurn(!game.getTurn());
                    } else {
                        game.playSound("/Error2.wav", soundOn);
                    }
                //white turn. set white piece    
                } else if (game.getTurn() == AllDef.WHITE) {
                    if (game.getWhite().setChess(x, y)) {

                        game.playSound("/Click3.wav", soundOn);
                        game.setTurn(!game.getTurn());
                    } else {
                        game.playSound("/Error2.wav", soundOn);
                    }
                }
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
            }
        }
    }

    public void run() {
        while (isStart == true) {
            try {
                keyPressed();
                draw();
                t.sleep(100);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

    //draw the game
    private void draw() {
        g.drawImage(imgGround, getWidth() / 2, getHeight() / 2, Graphics.VCENTER
                | Graphics.HCENTER);
        //run game
        if (AllDef.RUN == game.getState()) {
            drawRun();
        //game finished. draw score    
        } else if (AllDef.SCORE == game.getState()) {
            drawScore();
        }
        flushGraphics();
    }

    //draw board
    private void drawRun() {
        drawRect();
        drawBoard();
    }

    //draw chess board
    private void drawRect() {
        for (int i = 1; i <= 8; i++) {
            for (int j = 1; j <= 8; j++) {

                g.setColor(0x0000ff);
                g.drawRect(i * UNITX, j * UNITY + 2 * UNITY, UNITX, UNITY);
            }
        }
    }

    //draw the final scroe
    private void drawScore() {
        g.setColor(45, color, 50);
        g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN,
                Font.SIZE_LARGE));

        g.drawImage(imgGround, getWidth() / 2, getHeight() / 2,
                Graphics.VCENTER | Graphics.HCENTER);

        g.drawString(msgStr, getWidth() / 2, getHeight() / 2 - UNITY,
                Graphics.BASELINE | Graphics.HCENTER);

        String strBlack = game.getBlack().getName() + " : " + blackNum;
        String strWhite = game.getWhite().getName() + " : " + whiteNum;
        g.drawString(strBlack, getWidth() / 2, getHeight() / 2,
                Graphics.BASELINE | Graphics.HCENTER);
        g.drawString(strWhite, getWidth() / 2, getHeight() / 2 + UNITY,
                Graphics.BASELINE | Graphics.HCENTER);

        String record = game.getBlack().getName() + " vs "
                + game.getWhite().getName() + " " + blackNum + " : " + whiteNum + " " + msgStr;
        if (isSave == true) {
            saveRecord(record);
            uploadRecords();
            isSave = false;
        }
    }

    //draw all the pieces on board
    private void drawBoard() {
        LayerManager black = new LayerManager();
        LayerManager white = new LayerManager();
        ReversiSprite tmp = null;
        for (int i = 1; i <= 8; i++) {
            for (int j = 1; j <= 8; j++) {

                if (animationOn == true) {
                    if (game.getBlack().getChess(j, i) == null || game.getBlack().getOldChess(j, i) != null) {
                        continue;
                    } else if (AllDef.BLACK == game.getBlack().getChess(j, i).toBool()) {
                        mSprite.setPosition(i * UNITX, j * UNITY + 2 * UNITY);
                        mSprite.getBlack();
                        mSprite.paint(g);

                    } else if (AllDef.WHITE == game.getWhite().getChess(j, i).toBool()) {
                        mSprite.setPosition(i * UNITX, j * UNITY + 2 * UNITY);
                        mSprite.getWhite();
                        mSprite.paint(g);
                    }
                } else {
                    if (game.getBlack().getChess(j, i) == null) {
                        continue;
                    } else if (AllDef.BLACK == game.getBlack().getChess(j, i).toBool()) {
                        mSprite.setPosition(i * UNITX, j * UNITY + 2 * UNITY);
                        mSprite.getBlack();
                        mSprite.paint(g);

                    } else if (AllDef.WHITE == game.getWhite().getChess(j, i).toBool()) {
                        mSprite.setPosition(i * UNITX, j * UNITY + 2 * UNITY);
                        mSprite.getWhite();
                        mSprite.paint(g);
                    }
                }
            }
        }

        // flip the piece white to blace. black to white
        if (animationOn == true) {
            for (int i = 1; i <= 8; i++) {
                for (int j = 1; j <= 8; j++) {
                    if (game.getBlack().getOldChess(j, i) != null) {
                        if (game.getBlack().getOldChess(j, i).toBool() == AllDef.BLACK) {
                            tmp = createSprite(i * UNITX, j * UNITY + 2 * UNITY);
                            black.append(tmp);
                        } else if (game.getBlack().getOldChess(j, i).toBool() == AllDef.WHITE) {
                            tmp = createSprite(i * UNITX, j * UNITY + 2 * UNITY);
                            white.append(tmp);
                        }
                    }
                }
            }

            //flip white to black
            game.getBlack().initOldChess();
            if (black.getSize() != 0) {
                if (black != null) {
                    for (int i = 0; i < black.getSize(); i++) {
                        ReversiSprite tmpBlack = (ReversiSprite) black.getLayerAt(i);
                        tmpBlack.whiteChangeToBlack();
                    }
                    for (int z = 0; z < 3; z++) {
                        black.paint(g, 0, 0);
                        for (int i = 0; i < black.getSize(); i++) {
                            ReversiSprite tmpBlack = (ReversiSprite) black.getLayerAt(i);
                            tmpBlack.nextFrame();
                        }
                        flushGraphics(UNITX, 3 * UNITY, 8 * UNITX, 8 * UNITY);
                        if (z < 2) {
                            try {
                                t.sleep(100);
                            } catch (InterruptedException ex) {
                                ex.printStackTrace();
                            }
                        }
                    }
                }
            }

            //flip black to white
            if (white.getSize() != 0) {
                if (white != null) {
                    for (int i = 0; i < white.getSize(); i++) {
                        ReversiSprite tmpWhite = (ReversiSprite) white.getLayerAt(i);
                        tmpWhite.blackChangeToWhite();
                    }
                    tmp.blackChangeToWhite();
                    for (int z = 0; z < 3; z++) {
                        white.paint(g, 0, 0);
                        for (int i = 0; i < white.getSize(); i++) {
                            ReversiSprite tmpWhite = (ReversiSprite) white.getLayerAt(i);
                            tmpWhite.nextFrame();
                        }
                        flushGraphics(2 * UNITX, 3 * UNITY, 8 * UNITX, 8 * UNITY);
                        if (z < 2) {
                            try {
                                t.sleep(100);
                            } catch (InterruptedException ex) {
                                ex.printStackTrace();
                            }
                        }
                    }
                }
            }
        }

        //draw cursor
        g.setColor(rectColor);
        g.drawRect(y * UNITX, x * UNITY + 2 * UNITY, UNITX, UNITY);

        //draw game information and user information on board
        g.setFont(Font.getDefaultFont());
        g.setColor(0x0000ff);
        g.drawImage(imgBlack, UNITX + UNITX / 2, UNITY - 5 + UNITY / 2,
                Graphics.VCENTER | Graphics.HCENTER);
        g.drawImage(imgWhite, UNITX + UNITX / 2 + UNITX * 5, UNITY * 3 / 4 + UNITY / 2,
                Graphics.VCENTER | Graphics.HCENTER);
        String firstName = game.getBlack().getName() + " : " + game.getBlack().getNum();
        String secondName = game.getWhite().getName() + " : " + game.getWhite().getNum();
        g.drawString(firstName, getWidth() / 2 - 2 * UNITY, UNITY, Graphics.HCENTER | Graphics.TOP);
        g.drawString(secondName, getWidth() / 2 + 3 * UNITY, UNITY, Graphics.HCENTER | Graphics.TOP);
        other();
    }

    public void stop() {
        isStart = false;
    }

    public void start() {
        t = new Thread(this);
        t.start();
        isStart = true;
    }

    //check wins and turns
    private void other() {
        //NOSET
        String tmpString = null;
        if (AllDef.NOSET == game.getBlack().result()) {
            game.setTurn(AllDef.WHITE);

        }
        if (AllDef.NOSET == game.getWhite().result()) {
            game.setTurn(AllDef.BLACK);
        }

        //white and black can not set. Someone win
        if (AllDef.NOSET == game.getBlack().result()
                && AllDef.NOSET == game.getWhite().result()) {
            whiteNum = game.getWhite().getNum();
            blackNum = game.getBlack().getNum();

            if (game.getWhite().getNum() > game.getBlack().getNum()) {
                msgStr = game.getWhite().getName() + " Wins!";

            } else if (game.getWhite().getNum() < game.getBlack().getNum()) {
                msgStr = game.getBlack().getName() + " Wins!";
            } else {
                msgStr = "No winner";
                game.playSound("/Draw.wav", soundOn);
            }
            game.playSound("/Win.wav", soundOn);
            game.getBlack().init();
            game.getWhite().init();
            game.setState(AllDef.SCORE);
        }

        if (game.getTurn() == true) {
            tmpString = game.getWhite().getName() + " turn";
        } else {
            tmpString = game.getBlack().getName() + " turn";
        }
        g.drawString(tmpString, getWidth() / 2, 2 * UNITY - UNITY / 3, Graphics.HCENTER | Graphics.TOP);

        //WIN
        if (AllDef.WIN == game.getBlack().result()) {
            game.getBlack().init();
            msgStr = game.getBlack().getName() + " Wins!";
            game.playSound("/Win.wav", soundOn);
            game.setState(AllDef.SCORE);

        } else if (AllDef.WIN == game.getWhite().result()) {
            game.getWhite().init();
            msgStr = game.getWhite().getName() + " Wins!";
            game.playSound("/Win.wav", soundOn);
            game.setState(AllDef.SCORE);
        }

        // write win
        if (game.getBlack().getNum() == 0) {
            game.getWhite().init();
            msgStr = game.getWhite().getName() + " Wins!";
            game.playSound("/Win.wav", soundOn);
            game.setState(AllDef.SCORE);
        }

        //black win
        if (game.getWhite().getNum() == 0) {
            game.getBlack().init();
            msgStr = game.getBlack().getName() + " Wins!";
            game.playSound("/Win.wav", soundOn);
            game.setState(AllDef.SCORE);
        }

        // chec who wins
        if (game.getWhite().getNum() + game.getBlack().getNum() == 64) {
            whiteNum = game.getWhite().getNum();
            blackNum = game.getBlack().getNum();

            if (game.getWhite().getNum() > game.getBlack().getNum()) {
                msgStr = game.getWhite().getName() + " Wins!";

            } else if (game.getWhite().getNum() < game.getBlack().getNum()) {
                msgStr = game.getBlack().getName() + " Wins!";
            } else {
                msgStr = "No winner";
                game.playSound("/Draw.wav", soundOn);
            }
            game.playSound("/Win.wav", soundOn);
            game.getBlack().init();
            game.getWhite().init();
            game.setState(AllDef.SCORE);

        }
    }

    //create sprite 
    private ReversiSprite createSprite(int x, int y) {
        try {
            Image image = Image.createImage("/piece.png");
            image = TransImage.scale(image, 3 * UNITX, UNITY);
            ReversiSprite rs = new ReversiSprite(image, UNITX, UNITY);
            rs.setRefPixelPosition(x, y);
            return rs;
        } catch (IOException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    //saving record
    private void saveRecord(String record) {
        String records[] = new String[5];

        try {
            rs = RecordStore.openRecordStore("GameRecords", true);
            // if there are 5 records already, delete the oldest one and 
            // add a new oen
            if (rs.getNumRecords() == 5) {

                for (int i = 1; i < rs.getNumRecords() + 1; i++) {
                    byte b[] = rs.getRecord(i);
                    records[i - 1] = new String(b, 0, b.length);
                }
                rs.closeRecordStore();
                rs.deleteRecordStore("GameRecords");
                rs = RecordStore.openRecordStore("GameRecords", true);
                for (int i = 1; i < 5; i++) {
                    rs.addRecord(records[i].getBytes(), 0, records[i].getBytes().length);
                }
                rs.addRecord(record.getBytes(), 0, record.getBytes().length);
                rs.closeRecordStore();
            //add new records    
            } else {
                byte[] byteOutputData = record.getBytes();
                rs.addRecord(byteOutputData, 0, byteOutputData.length);
                rs.closeRecordStore();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    
    
    // set the animation and sound
    private void gameSeting() {
        byte[] sound = null;
        byte[] animation = null;
        String soundString = null;
        String animationString = null;
        try {
            gameSetting = RecordStore.openRecordStore("GameSetting", true);
            if (gameSetting.getNumRecords() == 0) {
                soundOn = true;
                animationOn = true;
                gameSetting.closeRecordStore();
            } else {
                sound = gameSetting.getRecord(1);
                animation = gameSetting.getRecord(2);
                gameSetting.closeRecordStore();
                soundString = new String(sound, 0, sound.length);
                animationString = new String(animation, 0, animation.length);

                if (soundString.toLowerCase().equals("on")) {
                    soundOn = true;
                } else {
                    soundOn = false;
                }

                if (animationString.toLowerCase().equals("on")) {
                    animationOn = true;
                } else {
                    animationOn = false;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //get all the records
    private String getAllRecords() {
        String records = "";
        String tmp;
        byte tmpByte[] = null;
        try {
            rs = RecordStore.openRecordStore("GameRecords", true);
            for (int i = 1; i < rs.getNumRecords(); i++) {
                byte b[] = rs.getRecord(i);
                tmp = new String(b, 0, b.length) + ";";
                records = records + tmp;
            }
            tmpByte = rs.getRecord(rs.getNumRecords());
            tmp = new String(tmpByte, 0, tmpByte.length);
            records = records + tmp;
            rs.closeRecordStore();
            return records;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //uploading all the records
    private void uploadRecords() {
        String records = getAllRecords();
        String url = "http://localhost/uploading.php";
        HttpConnection connection = null;
        InputStream is = null;
        OutputStream os = null;
        StringBuffer stringBuffer = new StringBuffer();

        try {
            connection = (HttpConnection) Connector.open(url);
            connection.setRequestMethod(HttpConnection.POST);
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setRequestProperty("User-Agent", "Profile/MIDP-2.1 Configuration/CLDC-1.1");
            connection.setRequestProperty("Content-Length", "" + records.getBytes().length);

            os = connection.openOutputStream();
            os.write(records.getBytes());
            os.flush();

            is = connection.openDataInputStream();
            int ch;
            while ((ch = is.read()) != -1) {
                stringBuffer.append((char) ch);
            }

            if (is != null) {
                is.close();
            }
            if (os != null) {
                os.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
